package com.hks360.car_treasure.util;


/**
 * 地图坐标转换 google,baidu,gps
 * 
 * @author lw
 * @Time 2015年4月16日18:19:16
 * 
 * */
public class CoordConverter {

	/**
	 * 用于构造地图中的坐标点
	 * 
	 * @author lw
	 * **/
	static public class MapPoint {

		private double lat;// 纬度
		private double lng;// 经度

		public MapPoint() {
		}

		public MapPoint(double lng, double lat) {
			this.lng = lng;
			this.lat = lat;
		}

		@Override
		public boolean equals(Object obj) {
			if (obj instanceof MapPoint) {
				MapPoint bmapPoint = (MapPoint) obj;
				return (bmapPoint.getLng() == lng && bmapPoint.getLat() == lat) ? true
						: false;
			} else {
				return false;
			}
		}

		public double getLat() {
			return lat;
		}

		public void setLat(double lat) {
			this.lat = lat;
		}

		public double getLng() {
			return lng;
		}

		public void setLng(double lng) {
			this.lng = lng;
		}

		@Override
		public String toString() {
			return "Point [lat=" + lat + ", lng=" + lng + "]";
		}

	}

	private static final double x_pi = Math.PI * 3000.0 / 180.0;

	private static final double pi = Math.PI;
	private static final double a = 6378245.0;
	private static final double ee = 0.00669342162296594323;

	/**
	 * gg_lat 纬度 gg_lon 经度 GCJ-02转换BD-09 Google地图经纬度转百度地图经纬度
	 * */
	public static MapPoint google_bd_encrypt(double gg_lat, double gg_lon) {
		MapPoint point = new MapPoint();
		double x = gg_lon, y = gg_lat;
		double z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * x_pi);
		double theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * x_pi);
		double bd_lon = z * Math.cos(theta) + 0.0065;
		double bd_lat = z * Math.sin(theta) + 0.006;
		point.setLat(bd_lat);
		point.setLng(bd_lon);
		return point;
	}

	/**
	 * wgLat 纬度 wgLon 经度 BD-09转换GCJ-02 百度转google
	 * */
	public static MapPoint bd_google_encrypt(double bd_lat, double bd_lon) {
		MapPoint point = new MapPoint();
		double x = bd_lon - 0.0065, y = bd_lat - 0.006;
		double z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi);
		double theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi);
		double gg_lon = z * Math.cos(theta);
		double gg_lat = z * Math.sin(theta);
		point.setLat(gg_lat);
		point.setLng(gg_lon);
		return point;
	}

	/**
	 * wgLat 纬度 wgLon 经度 WGS-84 到 GCJ-02 的转换（即 GPS 加偏）
	 * */
	public static MapPoint wgs_gcj_encrypts(double wgLat, double wgLon) {
		MapPoint point = new MapPoint();
		if (outOfChina(wgLat, wgLon)) {
			point.setLat(wgLat);
			point.setLng(wgLon);
			return point;
		}
		double dLat = transformLat(wgLon - 105.0, wgLat - 35.0);
		double dLon = transformLon(wgLon - 105.0, wgLat - 35.0);
		double radLat = wgLat / 180.0 * pi;
		double magic = Math.sin(radLat);
		magic = 1 - ee * magic * magic;
		double sqrtMagic = Math.sqrt(magic);
		dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
		dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi);
		double lat = wgLat + dLat;
		double lon = wgLon + dLon;
		point.setLat(lat);
		point.setLng(lon);
		return point;
	}

	private static final int KLD_KCODE_SYSTEM = 34;
	private static final int KOCDE_MAX_LENGTH = 4;
	private static final double KCODE_CENTER_LAT = 40.0f;
	private static final double KCODE_CENTER_LON = 105.0f;
	private static final int KCODE_X_Y_MAX_NAGATIVE = 1260000;
	private static final String KCODE_CHARS = "0123456789abcdefghijkmnpqrstuvwxyz";

	private static boolean ConvertTo34System2(int dwNumber, byte[] pKCode,
			boolean bNegative) {
		boolean bRet = true;
		int dwDivideBy34 = dwNumber;
		byte iModeOf34 = 0;
		int iCount = 0;
		int i = 0;

		// dwDivideBy34 = 1260000;
		byte[] gMyKCode = KCODE_CHARS.getBytes();
		do {
			iModeOf34 = (byte) (dwDivideBy34 % 34);
			dwDivideBy34 = dwDivideBy34 / 34;

			for (i = 0; i < KLD_KCODE_SYSTEM; i++) {
				if (iModeOf34 == gMyKCode[i]) {
					pKCode[iCount] = gMyKCode[i];
					iCount++;
					if (1 == iCount && bNegative) {
						pKCode[0]--;
					}

					break;
				}
			}

		} while (dwDivideBy34 > 0);

		return bRet;
	}

	private static boolean ConvertTo34System(int dwNumber, byte[] pKCode,
			boolean bNegative) {
		boolean bRet = true;
		int dwDivideBy34 = dwNumber;
		byte iModeOf34 = 0;
		int iCount = 0;

		do {
			iModeOf34 = (byte) (dwDivideBy34 % 34);
			dwDivideBy34 = dwDivideBy34 / 34;

			if (iModeOf34 <= 9) {
				pKCode[iCount] = (byte) ('0' + iModeOf34);
			} else if (iModeOf34 >= 10 && iModeOf34 <= 20) {
				pKCode[iCount] = (byte) ('a' + (iModeOf34 - 10));
			} else if (iModeOf34 >= 21 && iModeOf34 <= 22) {
				pKCode[iCount] = (byte) ('m' + (iModeOf34 - 21));
			} else if (iModeOf34 >= 23 && iModeOf34 <= 33) {
				pKCode[iCount] = (byte) ('p' + (iModeOf34 - 23));
			}
			iCount++;
			if (1 == iCount && bNegative) {
				pKCode[0]--;
			}

		} while (dwDivideBy34 > 0);

		return bRet;
	}

	/*
	 * 说明: iKCodeSize 的大小包含最后的 NULL
	 */
	static String KCodeToZeroPoint(double dLat, double dLon) {
		int dwTmpLat = 0;
		int dwTmpLon = 0;
		boolean bIsNegative = false;
		byte[] pKCodeLat = new byte[KOCDE_MAX_LENGTH];
		byte[] pKCodeLon = new byte[KOCDE_MAX_LENGTH];
		char pKCode = '0';
		String retKeyCode = null;
		if (null != pKCodeLat) {
			double dDiff = (dLat - KCODE_CENTER_LAT);

			if (dDiff < 0) {
				bIsNegative = true;
				dDiff = -dDiff;
				dwTmpLat = (int) ((dDiff * 3600) * 10); // 以 0.1 秒为单位
				dwTmpLat = KCODE_X_Y_MAX_NAGATIVE - dwTmpLat;
			} else {
				bIsNegative = false;
				dwTmpLat = (int) ((dDiff * 3600) * 10); // 以 0.1 秒为单位
			}
			ConvertTo34System(dwTmpLat, pKCodeLat, bIsNegative);
		}

		if (null != pKCodeLon) {
			double dDiff = (dLon - KCODE_CENTER_LON);

			if (dDiff < 0) {
				bIsNegative = true;
				dDiff = -dDiff;
				dwTmpLon = (int) ((dDiff * 3600) * 10); // 以 0.1 秒为单位
				dwTmpLon = KCODE_X_Y_MAX_NAGATIVE - dwTmpLon;
			} else {
				bIsNegative = false;
				dwTmpLon = (int) ((dDiff * 3600) * 10); // 以 0.1 秒为单位
			}
			ConvertTo34System(dwTmpLon, pKCodeLon, bIsNegative);
		}

		if (KCODE_CENTER_LAT == dLat || KCODE_CENTER_LON == dLon) {
			if (KCODE_CENTER_LAT == dLat && KCODE_CENTER_LON == dLon) {
				pKCode = '5';
			} else if (KCODE_CENTER_LAT == dLat) {
				if (dLon > KCODE_CENTER_LON) {
					pKCode = '6';
				} else {
					pKCode = '8';
				}
			} else if (KCODE_CENTER_LON == dLon) {
				if (dLat > KCODE_CENTER_LAT) {
					pKCode = '5';
				} else {
					pKCode = '7';
				}
			}
		} else {
			if (dLat > KCODE_CENTER_LAT) {
				if (dLon > KCODE_CENTER_LON) {
					pKCode = '5';
				} else {
					pKCode = '6';
				}
			} else {
				if (dLon > KCODE_CENTER_LON) {
					pKCode = '8';
				} else {
					pKCode = '7';
				}
			}
		}
		// wcscat_s(pKCode, iKCodeSize, pKCodeLon);
		// wcscat_s(pKCode, iKCodeSize, pKCodeLat);
		String retKcode = new String(pKCodeLon) + new String(pKCodeLat);
		retKeyCode = "" + pKCode + new String(pKCodeLon)
				+ new String(pKCodeLat);
		return retKeyCode;
	}

	public static void transform(double wgLat, double wgLon, double[] latlng) {
		if (outOfChina(wgLat, wgLon)) {
			latlng[0] = wgLat;
			latlng[1] = wgLon;
			return;
		}
		double dLat = transformLat(wgLon - 105.0, wgLat - 35.0);
		double dLon = transformLon(wgLon - 105.0, wgLat - 35.0);
		double radLat = wgLat / 180.0 * pi;
		double magic = Math.sin(radLat);
		magic = 1 - ee * magic * magic;
		double sqrtMagic = Math.sqrt(magic);
		dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
		dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi);
		latlng[0] = wgLat + dLat;
		latlng[1] = wgLon + dLon;
	}

	private static boolean outOfChina(double lat, double lon) {
		if (lon < 72.004 || lon > 137.8347)
			return true;
		if (lat < 0.8293 || lat > 55.8271)
			return true;
		return false;
	}

	private static double transformLat(double x, double y) {
		double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y
				+ 0.2 * Math.sqrt(Math.abs(x));
		ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
		ret += (20.0 * Math.sin(y * pi) + 40.0 * Math.sin(y / 3.0 * pi)) * 2.0 / 3.0;
		ret += (160.0 * Math.sin(y / 12.0 * pi) + 320 * Math.sin(y * pi / 30.0)) * 2.0 / 3.0;
		return ret;
	}

	private static double transformLon(double x, double y) {
		double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1
				* Math.sqrt(Math.abs(x));
		ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
		ret += (20.0 * Math.sin(x * pi) + 40.0 * Math.sin(x / 3.0 * pi)) * 2.0 / 3.0;
		ret += (150.0 * Math.sin(x / 12.0 * pi) + 300.0 * Math.sin(x / 30.0
				* pi)) * 2.0 / 3.0;
		return ret;
	}
}